Skip to content

Initial change to integrate Harper.js#3

Merged
cyanzhong merged 4 commits into
mainfrom
copilot/implement-proofreading-capability
Mar 13, 2026
Merged

Initial change to integrate Harper.js#3
cyanzhong merged 4 commits into
mainfrom
copilot/implement-proofreading-capability

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 13, 2026

Integrates Harper.js into MarkEdit as a real-time grammar checker using native CodeMirror primitives.

Changes

  • main.ts — Replaced test stub with MarkEdit.addExtension(proofreadingExtension()) per MarkEdit conventions
  • src/lint.ts — Cleaned up to export only the LocalLinter wrapper with binaryInlined
  • src/extension.ts — New file containing the CodeMirror extension:
    • StateField + StateEffect managing diagnostics and a mapped DecorationSet
    • ViewPlugin that debounces docChanged (500ms), runs Harper async, discards stale results
    • hoverTooltip rendering diagnostic title, message, and suggestion action buttons
    • Base theme with SVG wavy underlines and light/dark mode tooltip styles
    • All three SuggestionKind variants handled (Replace, Remove, InsertAfter)

Architecture

docChanged → ViewPlugin debounce → harper.lint(text) → setDiagnosticsEffect
  → StateField builds DecorationSet → inline underlines
  → hoverTooltip reads diagnostics → tooltip with action buttons → view.dispatch(changes)

All text rendering uses textContent to avoid XSS vectors from linter output.

Original prompt

This section details on the original issue you should resolve

<issue_title>Harper Prototype</issue_title>
<issue_description>## Goals

Implement a proofreading capability for MarkEdit based on Harper.js. The objective is to integrate Harper into the editor pipeline and surface grammar feedback through native CodeMirror mechanisms.

The implementation should:

  • Integrate Harper.js using the existing project scaffold.
  • Implement a repeated checking mechanism driven by CodeMirror’s updateListener, allowing the document to be analyzed incrementally as the editor state changes.
  • Use Harper’s linting APIs to analyze the editor content and produce diagnostics.
  • Render feedback through CodeMirror’s UI primitives, specifically decorations for inline highlights and tooltip for contextual explanations and suggestions.

The resulting behavior should resemble a typical real-time proofreading workflow: text changes trigger analysis, diagnostics are produced, and issues are surfaced inline with interactive UI elements.

References

Note that Obsidian is also built on CodeMirror and provides an existing Harper integration. However, the implementation in the Obsidian plugin is tightly coupled with Obsidian’s internal APIs. The intended approach here is to extract the relevant Harper integration logic, remove dependencies on Obsidian-specific infrastructure, and implement a clean MarkEdit extension using MarkEdit API.

Rules

  • Follow conventions established in the MarkEdit preview extension repository.
  • Prioritize a consistent and predictable user experience aligned with established editor best practices.
  • Prefer simple, maintainable implementations and concise code structure.</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI and others added 2 commits March 13, 2026 00:55
- Refactor src/lint.ts: clean Harper linter wrapper using LocalLinter
- Create src/extension.ts: CodeMirror extension with decorations, tooltips, and update listener
- Update main.ts: MarkEdit API integration using addExtension

Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
…nt for messages

Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Copilot AI changed the title [WIP] Add proofreading capability for MarkEdit using Harper.js Implement Harper.js proofreading extension for MarkEdit Mar 13, 2026
Copilot AI requested a review from cyanzhong March 13, 2026 00:58
Comment thread src/extension.ts Outdated
});

// Base theme for lint decorations and tooltips
const baseTheme = EditorView.baseTheme({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this file is currently not well organized because on purpose, try moving styling, decoration, and tooltip to dedicated files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split into dedicated files in cea8716: src/styling.ts (base theme), src/decoration.ts (diagnostics state field, types, lint-to-diagnostic conversion), src/tooltip.ts (hover tooltip rendering). extension.ts now only contains the lint scheduler and the composition.

Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Copilot AI requested a review from cyanzhong March 13, 2026 01:10
@cyanzhong
Copy link
Copy Markdown
Contributor

cyanzhong commented Mar 13, 2026

@copilot Just curious. CodeMirror is viewport based to handle long documents.

It means that the content you see on the screen isn't necessarily the full content.

Two questions:

  1. Is your current implementation robust enough to handle this?
  2. Instead of proofreading the full content, do you think a viewport based approach would be better for performance?

I don't want to look into the details, you tell me how good the performance and correctness is in the current implementation.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot Just curious. CodeMirror is viewport based to handle long documents.

It means that the content you see on the screen isn't necessarily the full content.
...

Good questions. Here's the analysis:

1. Correctness with viewport-based rendering: The implementation is robust. state.doc always contains the full document regardless of viewport — doc.sliceString(0) reads the complete text, so Harper analyzes everything. The DecorationSet stores decorations for the full document, and CodeMirror automatically filters to only render those intersecting the viewport. hoverTooltip only fires for visible positions. Position mapping via decorations.map(tr.changes) keeps everything consistent through edits. So the viewport layer is transparent to this implementation.

2. Viewport-based linting for performance: Full-document linting is the better choice here for a few reasons:

  • Harper needs sentence/paragraph context for accurate grammar checking — slicing to viewport boundaries would cut across sentences and produce incorrect or missing diagnostics.
  • Harper's WASM engine is designed to be fast; the 500ms debounce already prevents excessive re-linting, and the stale-result discard (this.view.state.doc !== doc) drops outdated results.
  • A viewport approach would require re-linting on scroll (not just on edits), merging partial results, and handling boundary sentences — significant complexity for marginal gain.

For very large documents (100k+ words), full-document linting could become noticeable, but for typical editing workloads this approach is both simpler and more correct. If perf becomes an issue in practice, the right optimization would likely be incremental/dirty-range tracking rather than viewport slicing.

@cyanzhong
Copy link
Copy Markdown
Contributor

This is a good start.

@cyanzhong cyanzhong marked this pull request as ready for review March 13, 2026 03:01
@cyanzhong cyanzhong changed the title Implement Harper.js proofreading extension for MarkEdit Initial change to integrate Harper.js Mar 13, 2026
@cyanzhong cyanzhong merged commit c9f78f7 into main Mar 13, 2026
1 check passed
@cyanzhong cyanzhong deleted the copilot/implement-proofreading-capability branch March 13, 2026 03:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harper prototype

2 participants